﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mogre;
using MogreNewt;

namespace WastedMechanics
{
    public class ProjectileBullet : Projectile
    {
        public Vector3 Direction;
        public Vector3 Origin;
        public float Speed;
        public float Damage;
        public int Ricochet;

        public BillboardChain BillboardChain;
        public SceneNode Node;

        public ProjectileBullet(object sender, Vector3 origin, Vector3 direction, float speed, float damage, string materialName)
            : base(sender)
        {            
            Direction = direction;
            Speed = speed;
            Damage = damage;

            Node = Engine.SceneManager.RootSceneNode.CreateChildSceneNode();
            Node.Position = origin;
            Origin = origin;

            BillboardChain = Engine.SceneManager.CreateBillboardChain();
            BillboardChain.SetMaterialName(materialName);
            BillboardChain.TextureCoordDirection = BillboardChain.TexCoordDirection.TCD_U;
            BillboardChain.Visible = true;
            BillboardChain.NumberOfChains = 1;
            BillboardChain.MaxChainElements = 3;

            BillboardChain.AddChainElement(0, BillboardChain.Element_NativePtr.Create(new Vector3(0, 0, 0), 0.01f, 0, new ColourValue(1, 1, 1, 0)));
            BillboardChain.AddChainElement(0, BillboardChain.Element_NativePtr.Create(new Vector3(0, 0, -3.75f), 0.02f, 0.5f, ColourValue.White));
            BillboardChain.AddChainElement(0, BillboardChain.Element_NativePtr.Create(new Vector3(0, 0, -4), 0.01f, 1, new ColourValue(1, 1, 1, 0)));

            Node.AttachObject(BillboardChain);
            Node.Orientation = Orientation;
            Node.SetVisible(false);
        }

        public override void Update()
        {
            if ((Origin - Node.Position).Length > 4)
                Node.SetVisible(true);

            Vector3 newPos = Position + Direction * Speed * Engine.FixedTimeStep;
            Raycaster.PredicateRaycast raycast = new Raycaster.PredicateRaycast(
                (body => (body.UserData != Sender || Ricochet > 0) 
                    && !(body.UserData is GameObject && (body.UserData as GameObject).IsObstacle == false))
                );            
            raycast.Go(Engine.NewtonWorld, Node.Position, newPos);
            if (raycast.Contacts.Count != 0)
            {
                raycast.SortContacts();

                if (raycast.Contacts[0].Body.MaterialGroupID != Engine.MaterialManager.Materials["Transparent"])
                {
                    if (raycast.Contacts[0].Body.UserData is Character)
                    {
                        Console.WriteLine("oww {0}", (raycast.Contacts[0].Body.UserData as Character).Label);
                        Character target = raycast.Contacts[0].Body.UserData as Character;
                        target.ReceiveDamage(Damage, Sender is SelectableObject ? (Sender as SelectableObject) : null);
                        Engine.ObjectManager.Destroy(this);
                    }
                    else if (raycast.Contacts[0].Body.UserData is Described)
                    {
                        Described target = raycast.Contacts[0].Body.UserData as Described;
                        target.GetHit(this, Node.Position + raycast.Contacts[0].Distance * (newPos - Node.Position));
                        Engine.ObjectManager.Destroy(this);
                    }
                    else
                    {
                        Direction = Direction.Reflect(raycast.Contacts[0].Normal);
                        Node.Orientation = Orientation;
                        Node.Position = Node.Position + (newPos - Node.Position) * raycast.Contacts[0].Distance;
                        Damage *= 0.5f;
                        if (Speed > 50)
                        {
                            if (Ricochet > 0)
                                Engine.ObjectManager.Destroy(this);
                            else
                            {
                                SoundInstance ricochet = Engine.SoundManager.SoundEffects["ricochet.wav"].PlayNewInstance();
                                ricochet.Volume = 0.6f;
                                ricochet.SetPosition(Node.Position);
                            }
                        }
                        else
                        {
                            SoundInstance blaster = Engine.SoundManager.SoundEffects["blaster.wav"].PlayNewInstance();
                            blaster.SetPosition(Node.Position);
                        }                            
                        Ricochet++;
                    }
                    
                }
                else
                    Move(newPos);
            }
            else
                Move(newPos);
                           
        }

        public void Move(Vector3 pos)
        {            
            Node.Position = pos;
            if ((Origin - Node.Position).Length > 3000)
                Engine.ObjectManager.Destroy(this);    
        }

        public override void Destroy()
        {
            Node.DetachAllObjects();
            Engine.SceneManager.DestroySceneNode(Node);
            Engine.SceneManager.DestroyBillboardChain(BillboardChain);
        }

        public override Vector3 Position
        {
            get
            {
                return Node.Position;
            }
            set
            {
                Node.Position = value;
            }
        }

        public override Quaternion Orientation
        {
            get
            {
                return Vector3.UNIT_Z.GetRotationTo(Direction);
            }
            set
            {
                Node.Orientation = value;
            }
        }

    }
}
